
<!DOCTYPE html>
<html lang="zh-Hans" class="loading">
<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>springboot2.0 mybatis 使用多数据源 - Luis Blog</title>
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <meta name="google" content="notranslate" />
    <meta name="keywords" content="Luis,"> 
    <meta name="description" content="java开发工程师，喜欢代码，喜欢技术,springboot2.0正式版发布之后，很多的组件集成需要变更了，这次将多数据源的使用踩的坑给大家填一填。当前多数据源的主要为主从库，读写分离，动态切换数据源。使用的技术就是AOP进行dao方法的,"> 
    <meta name="author" content="winter chen"> 
    <link rel="alternative" href="atom.xml" title="Luis Blog" type="application/atom+xml"> 
    <link rel="icon" href="/img/favicon.png"> 
    
    
<link rel="stylesheet" href="/css/diaspora.css">

	<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
    <script>
         (adsbygoogle = window.adsbygoogle || []).push({
              google_ad_client: "ca-pub-8691406134231910",
              enable_page_level_ads: true
         });
    </script>
    <script async custom-element="amp-auto-ads"
        src="https://cdn.ampproject.org/v0/amp-auto-ads-0.1.js">
    </script>
<meta name="generator" content="Hexo 4.2.0"></head>

<body class="loading">
    <span id="config-title" style="display:none">Luis Blog</span>
    <div id="loader"></div>
    <div id="single">
    <div id="top" style="display: block;">
    <div class="bar" style="width: 0;"></div>
    <a class="iconfont icon-home image-icon" href="javascript:;" data-url="https://blog.winterchen.com"></a>
    <div title="播放/暂停" class="iconfont icon-play"></div>
    <h3 class="subtitle">springboot2.0 mybatis 使用多数据源</h3>
    <div class="social">
        <div>
            <div class="share">
                <a title="获取二维码" class="iconfont icon-scan" href="javascript:;"></a>
            </div>
            <div id="qr"></div>
        </div>
    </div>
    <div class="scrollbar"></div>
</div>

    <div class="section">
        <div class="article">
    <div class='main'>
        <h1 class="title">springboot2.0 mybatis 使用多数据源</h1>
        <div class="stuff">
            <span>五月 30, 2018</span>
            
  <ul class="post-tags-list" itemprop="keywords"><li class="post-tags-list-item"><a class="post-tags-list-link" href="/tags/Spring-Boot/" rel="tag">Spring Boot</a></li><li class="post-tags-list-item"><a class="post-tags-list-link" href="/tags/mybatis/" rel="tag">mybatis</a></li></ul>


        </div>
        <div class="content markdown">
            <p><img src="http://img.winterchen.com/multi-database.png" alt="多数据源"><br>springboot2.0正式版发布之后，很多的组件集成需要变更了，这次将多数据源的使用踩的坑给大家填一填。当前多数据源的主要为主从库，读写分离，动态切换数据源。使用的技术就是AOP进行dao方法的切面，所以大家的方法名开头都需要按照规范进行编写，如：<code>get***</code>、<code>add***</code> 等等，</p>
<a id="more"></a>
<h2 id="起步基础"><a href="#起步基础" class="headerlink" title="起步基础"></a>起步基础</h2><p>本次的教程需要有springboot2.0集成mybatis 作为基础：</p>
<ul>
<li><p>博客地址：<a href="https://blog.csdn.net/Winter_chen001/article/details/80010967" target="_blank" rel="noopener">springboot2.0 Mybatis 整合 (springboot2.0版本)</a></p>
</li>
<li><p>基础项目源码：<a href="https://github.com/WinterChenS/springboot2-mybatis-demo" target="_blank" rel="noopener">https://github.com/WinterChenS/springboot2-mybatis-demo</a></p>
</li>
</ul>
<p>需要以上的步骤作为基础，运行成功之后可就可以开始配置多数据源了</p>
<h2 id="开始动手"><a href="#开始动手" class="headerlink" title="开始动手"></a>开始动手</h2><h3 id="添加依赖"><a href="#添加依赖" class="headerlink" title="添加依赖"></a>添加依赖</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;dependency&gt;</span><br><span class="line">  &lt;groupId&gt;org.springframework.boot&lt;&#x2F;groupId&gt;</span><br><span class="line">  &lt;artifactId&gt;spring-boot-starter-aop&lt;&#x2F;artifactId&gt;</span><br><span class="line">&lt;&#x2F;dependency&gt;</span><br></pre></td></tr></table></figure>

<h3 id="修改启动类"><a href="#修改启动类" class="headerlink" title="修改启动类"></a>修改启动类</h3><p>修改之前：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@MapperScan</span>(<span class="string">"com.winterchen.dao"</span>)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SpringBootMybatisMutilDatabaseApplication</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        SpringApplication.run(SpringBootMybatisMutilDatabaseApplication.class, args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>修改之后：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SpringBootMybatisMutilDatabaseApplication</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        SpringApplication.run(SpringBootMybatisMutilDatabaseApplication.class, args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>因为改用多数据源，所以dao接口的扫描我们放在配置类中进行</p>
<h3 id="修改项目配置"><a href="#修改项目配置" class="headerlink" title="修改项目配置"></a>修改项目配置</h3><p>首先我们需要在配置文件中配置多数据源，看一下原本项目的配置：</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line"><span class="attr">    datasource:</span></span><br><span class="line"><span class="attr">        name:</span> <span class="string">mysql_test</span></span><br><span class="line">        <span class="comment">#-----------------start-----------------#  （1）</span></span><br><span class="line"><span class="attr">        type:</span> <span class="string">com.alibaba.druid.pool.DruidDataSource</span></span><br><span class="line">        <span class="comment">#-----------------end-----------------#</span></span><br><span class="line">        <span class="comment">#druid相关配置</span></span><br><span class="line"><span class="attr">        druid:</span></span><br><span class="line">          <span class="comment">#监控统计拦截的filters</span></span><br><span class="line"><span class="attr">          filters:</span> <span class="string">stat</span></span><br><span class="line">          <span class="comment">#-----------------start-----------------# （2）</span></span><br><span class="line"><span class="attr">          driver-class-name:</span> <span class="string">com.mysql.jdbc.Driver</span></span><br><span class="line">          <span class="comment">#基本属性</span></span><br><span class="line"><span class="attr">          url:</span> <span class="attr">jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true&amp;characterEncoding=UTF-8&amp;allowMultiQueries=true</span></span><br><span class="line"><span class="attr">          username:</span> <span class="string">root</span></span><br><span class="line"><span class="attr">          password:</span> <span class="string">root</span></span><br><span class="line">           <span class="comment">#-----------------end-----------------#</span></span><br><span class="line">          <span class="comment">#配置初始化大小/最小/最大</span></span><br><span class="line"><span class="attr">          initial-size:</span> <span class="number">1</span></span><br><span class="line"><span class="attr">          min-idle:</span> <span class="number">1</span></span><br><span class="line"><span class="attr">          max-active:</span> <span class="number">20</span></span><br><span class="line">          <span class="comment">#获取连接等待超时时间</span></span><br><span class="line"><span class="attr">          max-wait:</span> <span class="number">60000</span></span><br><span class="line">          <span class="comment">#间隔多久进行一次检测，检测需要关闭的空闲连接</span></span><br><span class="line"><span class="attr">          time-between-eviction-runs-millis:</span> <span class="number">60000</span></span><br><span class="line">          <span class="comment">#一个连接在池中最小生存的时间</span></span><br><span class="line"><span class="attr">          min-evictable-idle-time-millis:</span> <span class="number">300000</span></span><br><span class="line"><span class="attr">          validation-query:</span> <span class="string">SELECT</span> <span class="string">'x'</span></span><br><span class="line"><span class="attr">          test-while-idle:</span> <span class="literal">true</span></span><br><span class="line"><span class="attr">          test-on-borrow:</span> <span class="literal">false</span></span><br><span class="line"><span class="attr">          test-on-return:</span> <span class="literal">false</span></span><br><span class="line">          <span class="comment">#打开PSCache，并指定每个连接上PSCache的大小。oracle设为true，mysql设为false。分库分表较多推荐设置为false</span></span><br><span class="line"><span class="attr">          pool-prepared-statements:</span> <span class="literal">false</span></span><br><span class="line"><span class="attr">          max-pool-prepared-statement-per-connection-size:</span> <span class="number">20</span></span><br></pre></td></tr></table></figure>

<p>*<em>需要修改的地方: *</em></p>
<ul>
<li><p>(1) 需要将 <code>type: com.alibaba.druid.pool.DruidDataSource</code>去除；</p>
</li>
<li><p>(2) 将关于数据库的连接信息: <code>driver-class-name</code>、<code>url</code>、<code>username</code> 、<code>password</code>  去除；</p>
</li>
</ul>
<p><strong>修改后：</strong></p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line"><span class="attr">    datasource:</span></span><br><span class="line"><span class="attr">        name:</span> <span class="string">mysql_test</span></span><br><span class="line">        <span class="comment">#-------------- start ----------------# (1)</span></span><br><span class="line"><span class="attr">        master:</span></span><br><span class="line">          <span class="comment">#基本属性--注意，这里的为【jdbcurl】-- 默认使用HikariPool作为数据库连接池</span></span><br><span class="line"><span class="attr">          jdbcurl:</span> <span class="attr">jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true&amp;characterEncoding=UTF-8&amp;allowMultiQueries=true</span></span><br><span class="line"><span class="attr">          username:</span> <span class="string">root</span></span><br><span class="line"><span class="attr">          password:</span> <span class="string">root</span></span><br><span class="line"><span class="attr">          driver-class-name:</span> <span class="string">com.mysql.jdbc.Driver</span></span><br><span class="line"><span class="attr">        slave:</span></span><br><span class="line">          <span class="comment">#基本属性--注意，这里为 【url】-- 使用 druid 作为数据库连接池</span></span><br><span class="line"><span class="attr">          url:</span> <span class="attr">jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true&amp;characterEncoding=UTF-8&amp;allowMultiQueries=true</span></span><br><span class="line"><span class="attr">          username:</span> <span class="string">root</span></span><br><span class="line"><span class="attr">          password:</span> <span class="string">root</span></span><br><span class="line"><span class="attr">          driver-class-name:</span> <span class="string">com.mysql.jdbc.Driver</span></span><br><span class="line"><span class="attr">        read:</span> <span class="string">get,select,count,list,query,find</span></span><br><span class="line"><span class="attr">        write:</span> <span class="string">add,create,update,delete,remove,insert</span></span><br><span class="line">        <span class="comment">#-------------- end ----------------#</span></span><br><span class="line">        <span class="comment">#druid相关配置</span></span><br><span class="line"><span class="attr">        druid:</span></span><br><span class="line">          <span class="comment">#监控统计拦截的filters</span></span><br><span class="line"><span class="attr">          filters:</span> <span class="string">stat,wall</span></span><br><span class="line">          <span class="comment">#配置初始化大小/最小/最大</span></span><br><span class="line"><span class="attr">          initial-size:</span> <span class="number">1</span></span><br><span class="line"><span class="attr">          min-idle:</span> <span class="number">1</span></span><br><span class="line"><span class="attr">          max-active:</span> <span class="number">20</span></span><br><span class="line">          <span class="comment">#获取连接等待超时时间</span></span><br><span class="line"><span class="attr">          max-wait:</span> <span class="number">60000</span></span><br><span class="line">          <span class="comment">#间隔多久进行一次检测，检测需要关闭的空闲连接</span></span><br><span class="line"><span class="attr">          time-between-eviction-runs-millis:</span> <span class="number">60000</span></span><br><span class="line">          <span class="comment">#一个连接在池中最小生存的时间</span></span><br><span class="line"><span class="attr">          min-evictable-idle-time-millis:</span> <span class="number">300000</span></span><br><span class="line"><span class="attr">          validation-query:</span> <span class="string">SELECT</span> <span class="string">'x'</span></span><br><span class="line"><span class="attr">          test-while-idle:</span> <span class="literal">true</span></span><br><span class="line"><span class="attr">          test-on-borrow:</span> <span class="literal">false</span></span><br><span class="line"><span class="attr">          test-on-return:</span> <span class="literal">false</span></span><br><span class="line">          <span class="comment">#打开PSCache，并指定每个连接上PSCache的大小。oracle设为true，mysql设为false。分库分表较多推荐设置为false</span></span><br><span class="line"><span class="attr">          pool-prepared-statements:</span> <span class="literal">false</span></span><br><span class="line"><span class="attr">          max-pool-prepared-statement-per-connection-size:</span> <span class="number">20</span></span><br></pre></td></tr></table></figure>

<p>需要修改地方：</p>
<ul>
<li>(1) 在如上的配置中添加<code>master</code>、<code>slave</code>两个数据源;</li>
</ul>
<p><strong>注意！！</strong>两中数据源中有一处是不一样的，原因是因为<code>master</code>数据源使用 <code>Hikari</code>连接池，<code>slave</code>使用的是<code>druid</code>作为数据库连接池，所以两处的配置分别为：</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">master:</span></span><br><span class="line"><span class="attr">    jdbcurl:</span> <span class="attr">jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true&amp;characterEncoding=UTF-8&amp;allowMultiQueries=true</span></span><br></pre></td></tr></table></figure>

<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">slave:</span></span><br><span class="line"><span class="attr">    url:</span> <span class="attr">jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true&amp;characterEncoding=UTF-8&amp;allowMultiQueries=true</span></span><br></pre></td></tr></table></figure>

<p>数据库的连接不一样的，如果配置成一样的会在启动的时候报错。</p>
<p><strong>注意！！</strong></p>
<p>dao接口方法的方法名规则配置在这里了，当然可以自行更改：</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">read:</span> <span class="string">get,select,count,list,query,find</span></span><br><span class="line"><span class="attr">write:</span> <span class="string">add,create,update,delete,remove,insert</span></span><br></pre></td></tr></table></figure>

<h3 id="创建配置包"><a href="#创建配置包" class="headerlink" title="创建配置包"></a>创建配置包</h3><p>首先在项目的<code>/src/main/java/com/winterchen/</code>包下创建<code>config</code>包</p>
<p><img src="http://img.winterchen.com/WX20180530-163257@2x.png" alt="创建config包"></p>
<h3 id="创建数据源类型的枚举DatabaseType"><a href="#创建数据源类型的枚举DatabaseType" class="headerlink" title="创建数据源类型的枚举DatabaseType"></a>创建数据源类型的枚举DatabaseType</h3><p>该枚举类主要用来区分读写</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.winterchen.config;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 列出数据源类型</span></span><br><span class="line"><span class="comment"> * Created by Donghua.Chen on 2018/5/29.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">enum</span> DatabaseType &#123;</span><br><span class="line"></span><br><span class="line">    master(<span class="string">"write"</span>), slave(<span class="string">"read"</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    DatabaseType(String name) &#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">"DatabaseType&#123;"</span> +</span><br><span class="line">                <span class="string">"name='"</span> + name + <span class="string">'\''</span> +</span><br><span class="line">                <span class="string">'&#125;'</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="创建线程安全的DatabaseType容器"><a href="#创建线程安全的DatabaseType容器" class="headerlink" title="创建线程安全的DatabaseType容器"></a>创建线程安全的DatabaseType容器</h3><p>多数据源必须要保证数据源的线程安全的</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.winterchen.config;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 保存一个线程安全的DatabaseType容器</span></span><br><span class="line"><span class="comment"> * Created by Donghua.Chen on 2018/5/29.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DatabaseContextHolder</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//用于存放多线程环境下的成员变量</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> ThreadLocal&lt;DatabaseType&gt; contextHolder = <span class="keyword">new</span> ThreadLocal&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">setDatabaseType</span><span class="params">(DatabaseType type)</span> </span>&#123;</span><br><span class="line">        contextHolder.set(type);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> DatabaseType <span class="title">getDatabaseType</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> contextHolder.get();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="创建动态数据源"><a href="#创建动态数据源" class="headerlink" title="创建动态数据源"></a>创建动态数据源</h3><p>实现数据源切换的功能就是自定义一个类扩展AbstractRoutingDataSource抽象类，其实该相当于数据源DataSource的路由中介，可以实现在项目运行时根据相应key值切换到对应的数据源DataSource上，有兴趣的同学可以看看它的源码。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DynamicDataSource</span> <span class="keyword">extends</span> <span class="title">AbstractRoutingDataSource</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> Map&lt;DatabaseType, List&lt;String&gt;&gt; METHOD_TYPE_MAP = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="meta">@Nullable</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> Object <span class="title">determineCurrentLookupKey</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        DatabaseType type = DatabaseContextHolder.getDatabaseType();</span><br><span class="line">        logger.info(<span class="string">"====================dataSource =========="</span> + type);</span><br><span class="line">        <span class="keyword">return</span> type;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">setMethodType</span><span class="params">(DatabaseType type, String content)</span> </span>&#123;</span><br><span class="line">        List&lt;String&gt; list = Arrays.asList(content.split(<span class="string">","</span>));</span><br><span class="line">        METHOD_TYPE_MAP.put(type, list);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="创建数据源配置类DataSourceConfig"><a href="#创建数据源配置类DataSourceConfig" class="headerlink" title="创建数据源配置类DataSourceConfig"></a>创建数据源配置类DataSourceConfig</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@MapperScan</span>(<span class="string">"com.winterchen.dao"</span>)</span><br><span class="line"><span class="meta">@EnableTransactionManagement</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DataSourceConfig</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> Logger logger = LoggerFactory.getLogger(DataSourceConfig.class);</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> Environment env;  <span class="comment">// (1)</span></span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> DataSourceProperties properties;  <span class="comment">// (2)</span></span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value</span>(<span class="string">"$&#123;spring.datasource.druid.filters&#125;"</span>)   <span class="comment">// (3)</span></span><br><span class="line">    <span class="keyword">private</span> String filters;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value</span>(<span class="string">"$&#123;spring.datasource.druid.initial-size&#125;"</span>)</span><br><span class="line">    <span class="keyword">private</span> Integer initialSize;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value</span>(<span class="string">"$&#123;spring.datasource.druid.min-idle&#125;"</span>)</span><br><span class="line">    <span class="keyword">private</span> Integer minIdle;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value</span>(<span class="string">"$&#123;spring.datasource.druid.max-active&#125;"</span>)</span><br><span class="line">    <span class="keyword">private</span> Integer maxActive;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value</span>(<span class="string">"$&#123;spring.datasource.druid.max-wait&#125;"</span>)</span><br><span class="line">    <span class="keyword">private</span> Integer maxWait;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value</span>(<span class="string">"$&#123;spring.datasource.druid.time-between-eviction-runs-millis&#125;"</span>)</span><br><span class="line">    <span class="keyword">private</span> Long timeBetweenEvictionRunsMillis;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value</span>(<span class="string">"$&#123;spring.datasource.druid.min-evictable-idle-time-millis&#125;"</span>)</span><br><span class="line">    <span class="keyword">private</span> Long minEvictableIdleTimeMillis;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value</span>(<span class="string">"$&#123;spring.datasource.druid.validation-query&#125;"</span>)</span><br><span class="line">    <span class="keyword">private</span> String validationQuery;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value</span>(<span class="string">"$&#123;spring.datasource.druid.test-while-idle&#125;"</span>)</span><br><span class="line">    <span class="keyword">private</span> Boolean testWhileIdle;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value</span>(<span class="string">"$&#123;spring.datasource.druid.test-on-borrow&#125;"</span>)</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">boolean</span> testOnBorrow;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value</span>(<span class="string">"$&#123;spring.datasource.druid.test-on-return&#125;"</span>)</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">boolean</span> testOnReturn;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value</span>(<span class="string">"$&#123;spring.datasource.druid.pool-prepared-statements&#125;"</span>)</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">boolean</span> poolPreparedStatements;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Value</span>(<span class="string">"$&#123;spring.datasource.druid.max-pool-prepared-statement-per-connection-size&#125;"</span>)</span><br><span class="line">    <span class="keyword">private</span> Integer maxPoolPreparedStatementPerConnectionSize;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 通过Spring JDBC 快速创建 DataSource</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Bean</span>(name = <span class="string">"masterDataSource"</span>)</span><br><span class="line">    <span class="meta">@Qualifier</span>(<span class="string">"masterDataSource"</span>)</span><br><span class="line">    <span class="meta">@ConfigurationProperties</span>(prefix = <span class="string">"spring.datasource.master"</span>)  <span class="comment">// (4)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> DataSource <span class="title">masterDataSource</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> DataSourceBuilder.create().build();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 手动创建DruidDataSource,通过DataSourceProperties 读取配置</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> SQLException</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Bean</span>(name = <span class="string">"slaveDataSource"</span>)</span><br><span class="line">    <span class="meta">@Qualifier</span>(<span class="string">"slaveDataSource"</span>)</span><br><span class="line">    <span class="meta">@ConfigurationProperties</span>(prefix = <span class="string">"spring.datasource.slave"</span>)</span><br><span class="line">    <span class="function"><span class="keyword">public</span> DataSource <span class="title">slaveDataSource</span><span class="params">()</span> <span class="keyword">throws</span> SQLException </span>&#123;</span><br><span class="line">        DruidDataSource dataSource = <span class="keyword">new</span> DruidDataSource();</span><br><span class="line">        dataSource.setFilters(filters);</span><br><span class="line">        dataSource.setUrl(properties.getUrl());</span><br><span class="line">        dataSource.setDriverClassName(properties.getDriverClassName());</span><br><span class="line">        dataSource.setUsername(properties.getUsername());</span><br><span class="line">        dataSource.setPassword(properties.getPassword());</span><br><span class="line">        dataSource.setInitialSize(initialSize);</span><br><span class="line">        dataSource.setMinIdle(minIdle);</span><br><span class="line">        dataSource.setMaxActive(maxActive);</span><br><span class="line">        dataSource.setMaxWait(maxWait);</span><br><span class="line">        dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);</span><br><span class="line">        dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);</span><br><span class="line">        dataSource.setValidationQuery(validationQuery);</span><br><span class="line">        dataSource.setTestWhileIdle(testWhileIdle);</span><br><span class="line">        dataSource.setTestOnBorrow(testOnBorrow);</span><br><span class="line">        dataSource.setTestOnReturn(testOnReturn);</span><br><span class="line">        dataSource.setPoolPreparedStatements(poolPreparedStatements);</span><br><span class="line">        dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);</span><br><span class="line">        <span class="keyword">return</span> dataSource;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     *  构造多数据源连接池</span></span><br><span class="line"><span class="comment">     *  Master 数据源连接池采用 HikariDataSource</span></span><br><span class="line"><span class="comment">     *  Slave  数据源连接池采用 DruidDataSource</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> master</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> slave</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="meta">@Primary</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> DynamicDataSource <span class="title">dataSource</span><span class="params">(@Qualifier(<span class="string">"masterDataSource"</span>)</span> DataSource master,</span></span><br><span class="line"><span class="function">                                        @<span class="title">Qualifier</span><span class="params">(<span class="string">"slaveDataSource"</span>)</span> DataSource slave) </span>&#123;</span><br><span class="line">        Map&lt;Object, Object&gt; targetDataSources = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">        targetDataSources.put(DatabaseType.master, master);</span><br><span class="line">        targetDataSources.put(DatabaseType.slave, slave);</span><br><span class="line"></span><br><span class="line">        DynamicDataSource dataSource = <span class="keyword">new</span> DynamicDataSource();</span><br><span class="line">        dataSource.setTargetDataSources(targetDataSources);<span class="comment">// 该方法是AbstractRoutingDataSource的方法</span></span><br><span class="line">        dataSource.setDefaultTargetDataSource(slave);<span class="comment">// 默认的datasource设置为myTestDbDataSource</span></span><br><span class="line"></span><br><span class="line">        String read = env.getProperty(<span class="string">"spring.datasource.read"</span>);</span><br><span class="line">        dataSource.setMethodType(DatabaseType.slave, read);</span><br><span class="line"></span><br><span class="line">        String write = env.getProperty(<span class="string">"spring.datasource.write"</span>);</span><br><span class="line">        dataSource.setMethodType(DatabaseType.master, write);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> dataSource;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> SqlSessionFactory <span class="title">sqlSessionFactory</span><span class="params">(@Qualifier(<span class="string">"masterDataSource"</span>)</span> DataSource myTestDbDataSource,</span></span><br><span class="line"><span class="function">                                               @<span class="title">Qualifier</span><span class="params">(<span class="string">"slaveDataSource"</span>)</span> DataSource myTestDb2DataSource) <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        SqlSessionFactoryBean fb = <span class="keyword">new</span> SqlSessionFactoryBean();</span><br><span class="line">        fb.setDataSource(<span class="keyword">this</span>.dataSource(myTestDbDataSource, myTestDb2DataSource));</span><br><span class="line">        fb.setTypeAliasesPackage(env.getProperty(<span class="string">"mybatis.type-aliases-package"</span>));</span><br><span class="line">        fb.setMapperLocations(<span class="keyword">new</span> PathMatchingResourcePatternResolver().getResources(env.getProperty(<span class="string">"mybatis.mapper-locations"</span>)));</span><br><span class="line">        <span class="keyword">return</span> fb.getObject();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> DataSourceTransactionManager <span class="title">transactionManager</span><span class="params">(DynamicDataSource dataSource)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> DataSourceTransactionManager(dataSource);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>以上的代码中：</p>
<ul>
<li><p>(1)  注入类 <code>Environment</code> 可以很方便的获取配置文件中的参数</p>
</li>
<li><p>(2)  <code>DataSourceProperties</code>和（4）中的 <code>@ConfigurationProperties(prefix = &quot;spring.datasource.master&quot;)</code>配合使用，将配置文件中的配置数据自动封装到实体类<code>DataSourceProperties</code>中</p>
</li>
<li><p>(3) <code>@Value</code>注解同样是指定获取配置文件中的配置;</p>
</li>
</ul>
<p>更详细的配置大家可以参考官方文档。</p>
<h3 id="配置AOP"><a href="#配置AOP" class="headerlink" title="配置AOP"></a>配置AOP</h3><p>本章的开头已经说过，多数据源动态切换的原理是利用AOP切面进行动态的切换的，当调用<code>dao</code>接口方法时，根据接口方法的方法名开头进行区分读写。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * 动态处理数据源，根据命名区分</span></span><br><span class="line"><span class="comment"> * Created by Donghua.Chen on 2018/5/29.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Aspect</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@EnableAspectJAutoProxy</span>(proxyTargetClass = <span class="keyword">true</span>)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DataSourceAspect</span> </span>&#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> Logger logger = LoggerFactory.getLogger(DataSourceAspect.class);</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Pointcut</span>(<span class="string">"execution(* com.winterchen.dao.*.*(..))"</span>)<span class="comment">//切点</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">aspect</span><span class="params">()</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="meta">@Before</span>(<span class="string">"aspect()"</span>)</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">before</span><span class="params">(JoinPoint point)</span> </span>&#123; <span class="comment">//在指定切点的方法之前执行</span></span><br><span class="line">        String className = point.getTarget().getClass().getName();</span><br><span class="line">        String method = point.getSignature().getName();</span><br><span class="line">        String args = StringUtils.join(point.getArgs(), <span class="string">","</span>);</span><br><span class="line">        logger.info(<span class="string">"className:&#123;&#125;, method:&#123;&#125;, args:&#123;&#125; "</span>, className, method, args);</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">for</span> (DatabaseType type : DatabaseType.values()) &#123;</span><br><span class="line">                List&lt;String&gt; values = DynamicDataSource.METHOD_TYPE_MAP.get(type);</span><br><span class="line">                <span class="keyword">for</span> (String key : values) &#123;</span><br><span class="line">                    <span class="keyword">if</span> (method.startsWith(key)) &#123;</span><br><span class="line">                        logger.info(<span class="string">"&gt;&gt;&#123;&#125; 方法使用的数据源为:&#123;&#125;&lt;&lt;"</span>, method, key);</span><br><span class="line">                        DatabaseContextHolder.setDatabaseType(type);</span><br><span class="line">                        DatabaseType types = DatabaseContextHolder.getDatabaseType();</span><br><span class="line">                        logger.info(<span class="string">"&gt;&gt;&#123;&#125;方法使用的数据源为:&#123;&#125;&lt;&lt;"</span>, method, types);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            logger.error(e.getMessage(), e);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>如上可以看到，切点切在<code>dao</code>的接口方法中，根据接口方法的方法名进行匹配数据源，然后将数据源set到用于存放数据源线程安全的容器中；</p>
<p>完整的项目结构了解一下：</p>
<p><img src="http://img.winterchen.com/WX20180530-172445@2x.png" alt="完整项目结构"></p>
<h2 id="项目启动"><a href="#项目启动" class="headerlink" title="项目启动"></a>项目启动</h2><p>启动成功：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">2018-05-30 17:27:16.492  INFO 35406 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Located MBean &#39;masterDataSource&#39;: registering with JMX server as MBean [com.zaxxer.hikari:name&#x3D;masterDataSource,type&#x3D;HikariDataSource]</span><br><span class="line">2018-05-30 17:27:16.496  INFO 35406 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Located MBean &#39;slaveDataSource&#39;: registering with JMX server as MBean [com.alibaba.druid.pool:name&#x3D;slaveDataSource,type&#x3D;DruidDataSource]</span><br><span class="line">2018-05-30 17:27:16.498  INFO 35406 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Located MBean &#39;statFilter&#39;: registering with JMX server as MBean [com.alibaba.druid.filter.stat:name&#x3D;statFilter,type&#x3D;StatFilter]</span><br><span class="line">2018-05-30 17:27:16.590  INFO 35406 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path &#39;&#39;</span><br><span class="line">2018-05-30 17:27:16.598  INFO 35406 --- [           main] pringBootMybatisMutilDatabaseApplication : Started SpringBootMybatisMutilDatabaseApplication in 11.523 seconds (JVM running for 13.406)</span><br></pre></td></tr></table></figure>

<p>添加用户（write）：</p>
<p><img src="http://img.winterchen.com/WX20180530-172930@2x.png" alt="添加用户"></p>
<p>日志：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">2018-05-30 17:29:07.347  INFO 35406 --- [nio-8080-exec-1] com.winterchen.config.DataSourceAspect   : className:com.sun.proxy.$Proxy73, method:insert, args:com.winterchen.model.UserDomain@4b5b52dc</span><br><span class="line">2018-05-30 17:29:07.350  INFO 35406 --- [nio-8080-exec-1] com.winterchen.config.DataSourceAspect   : &gt;&gt;insert 方法使用的数据源为:insert&lt;&lt;</span><br><span class="line">2018-05-30 17:29:07.351  INFO 35406 --- [nio-8080-exec-1] com.winterchen.config.DataSourceAspect   : &gt;&gt;insert方法使用的数据源为:DatabaseType&#123;name&#x3D;&#39;write&#39;&#125;&lt;&lt;</span><br><span class="line">2018-05-30 17:29:07.461  INFO 35406 --- [nio-8080-exec-1] com.winterchen.config.DynamicDataSource  : &#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;dataSource &#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;DatabaseType&#123;name&#x3D;&#39;write&#39;&#125;</span><br><span class="line">2018-05-30 17:29:07.462  INFO 35406 --- [nio-8080-exec-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...</span><br><span class="line">2018-05-30 17:29:07.952  INFO 35406 --- [nio-8080-exec-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.</span><br></pre></td></tr></table></figure>

<p>可以看出使用的就是<code>write</code>数据源，并且该数据源是使用<code>HikariPool</code>作为数据库连接池的</p>
<p>查询用户（read）：</p>
<p><img src="http://img.winterchen.com/WX20180530-172958@2x.png" alt="查询用户"></p>
<p>日志：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">2018-05-30 17:29:41.616  INFO 35406 --- [nio-8080-exec-2] com.winterchen.config.DataSourceAspect   : className:com.sun.proxy.$Proxy73, method:selectUsers, args:</span><br><span class="line">2018-05-30 17:29:41.618  INFO 35406 --- [nio-8080-exec-2] com.winterchen.config.DataSourceAspect   : &gt;&gt;selectUsers 方法使用的数据源为:select&lt;&lt;</span><br><span class="line">2018-05-30 17:29:41.618  INFO 35406 --- [nio-8080-exec-2] com.winterchen.config.DataSourceAspect   : &gt;&gt;selectUsers方法使用的数据源为:DatabaseType&#123;name&#x3D;&#39;read&#39;&#125;&lt;&lt;</span><br><span class="line">2018-05-30 17:29:41.693  INFO 35406 --- [nio-8080-exec-2] com.winterchen.config.DynamicDataSource  : &#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;dataSource &#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;&#x3D;DatabaseType&#123;name&#x3D;&#39;read&#39;&#125;</span><br><span class="line">2018-05-30 17:29:41.982  INFO 35406 --- [nio-8080-exec-2] com.alibaba.druid.pool.DruidDataSource   : &#123;dataSource-1&#125; inited</span><br></pre></td></tr></table></figure>

<p>可以看出使用的是<code>read</code>数据源。</p>
<p>源码地址：<a href="https://github.com/WinterChenS/springboot-learning-experience/tree/master/spring-boot-mybatis-mutil-database" target="_blank" rel="noopener">戳这里</a></p>
<p>springboot技术交流群：681513531</p>

            <!--[if lt IE 9]><script>document.createElement('audio');</script><![endif]-->
            <audio id="audio" loop="1" preload="auto" controls="controls" data-autoplay="false">
                <source type="audio/mpeg" src="">
            </audio>
            
                <ul id="audio-list" style="display:none">
                    
                        
                            <li title='0' data-url='https://raw.githubusercontent.com/WinterChenS/imgrpo/master/mp3/%E6%96%B0%E8%A3%A4%E5%AD%90-%E7%94%9F%E6%B4%BB%E5%9B%A0%E4%BD%A0%E8%80%8C%E7%81%AB%E7%83%AD.mp3'></li>
                        
                    
                </ul>
            
        </div>
        
    <div id='gitalk-container' class="comment link"
		data-enable='false'
        data-ae='false'
        data-ci='77f2adc33e0112d086d7'
        data-cs='e926aa3a621556609b2c2b76d89320fa524e23cd'
        data-r='WinterChenS.github.io'
        data-o='WinterChenS'
        data-a='WinterChenS'
        data-d='false'
    >查看评论</div>


    </div>
    
</div>


    </div>
</div>
</body>


<script src="//lib.baomitu.com/jquery/1.8.3/jquery.min.js"></script>
<script src="/js/plugin.js"></script>
<script src="/js/typed.js"></script>
<script src="/js/diaspora.js"></script>


<link rel="stylesheet" href="/photoswipe/photoswipe.css">
<link rel="stylesheet" href="/photoswipe/default-skin/default-skin.css">


<script src="/photoswipe/photoswipe.min.js"></script>
<script src="/photoswipe/photoswipe-ui-default.min.js"></script>


<!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">
    <!-- Background of PhotoSwipe. 
         It's a separate element as animating opacity is faster than rgba(). -->
    <div class="pswp__bg"></div>
    <!-- Slides wrapper with overflow:hidden. -->
    <div class="pswp__scroll-wrap">
        <!-- Container that holds slides. 
            PhotoSwipe keeps only 3 of them in the DOM to save memory.
            Don't modify these 3 pswp__item elements, data is added later on. -->
        <div class="pswp__container">
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
        </div>
        <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
        <div class="pswp__ui pswp__ui--hidden">
            <div class="pswp__top-bar">
                <!--  Controls are self-explanatory. Order can be changed. -->
                <div class="pswp__counter"></div>
                <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>
                <button class="pswp__button pswp__button--share" title="Share"></button>
                <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>
                <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>
                <!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
                <!-- element will get class pswp__preloader--active when preloader is running -->
                <div class="pswp__preloader">
                    <div class="pswp__preloader__icn">
                      <div class="pswp__preloader__cut">
                        <div class="pswp__preloader__donut"></div>
                      </div>
                    </div>
                </div>
            </div>
            <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
                <div class="pswp__share-tooltip"></div> 
            </div>
            <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
            </button>
            <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
            </button>
            <div class="pswp__caption">
                <div class="pswp__caption__center"></div>
            </div>
        </div>
    </div>
</div>





<!-- Google Analytics -->
<script type="text/javascript">
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'G-30C04D6TMS', 'auto');
  ga('send', 'pageview');
</script>
<!-- End Google Analytics -->


</html>
